#include <fstream>
#include <boost/filesystem/path.hpp>
#include <iostream>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <boost/lexical_cast.hpp>
#include "CmdLine/cmdargs.h"
#include "stlhelper.h"
#include <boost/regex.hpp>
#include <boost/filesystem/path.hpp>
#include "get_arg.h"
using std::string;
using std::ofstream;
using std::ifstream;
using std::cerr;
using std::cout;
using std::max;
using boost::lexical_cast;



//_______________________________________________________________________________________

//		GetArguments

//				from command line
//				Created [9/13/2001]

//_______________________________________________________________________________________
bool GetArguments(int argc, char* argv[], t_program_args& args)
{
	// optional help directive
	CmdArgUsage opt_help('h', "help", 	"display this message", &cout);
	CmdArgSet opt_verbose('v', "verbose","issue lots more messages.");

	// required options
	const unsigned REQUIRED = CmdArg::isREQ | CmdArg::isVALREQ;
	CmdArgStr opt_dbname		('d', "dbname", "<string>",
								"PostgreSQL database name.",
								REQUIRED);
	CmdArgStr opt_host			('h', "host", "<string>",
								"PostgreSQL database host computer address.");
	CmdArgStr opt_user			('u', "user", "<string>",
								"PostgreSQL database user name. Defaults to 'postgres'.");
	CmdArgStr opt_password		('p', "password", "<string>",
								"PostgreSQL database password.");
	CmdArgStr opt_login			('l', "login", "<string>",
								"Other PostgreSQL login parameters in the form of "
								"keyword = value. E.g \"port=1234\".");
	
	
	CmdArgStr opt_job_category 	('j', "job_category", "<string>",
								"Postgres Batch table category for this job.",
								REQUIRED);
	CmdArgStr opt_output_table	('o', "output_table", "<string>",
								"Postgres table holding the results. See below.",
								REQUIRED);
	CmdArgStr opt_error_table	('f', "failed", "<string>",
								"Postgres table holding alignment failures. See below.",
								REQUIRED);
	CmdArgStr opt_map_table		('m', "map_table", "<string>",
								"Postgres table linking genes to proteins. "
								"Defaults to ens_id. See below.");
	opt_map_table = "ens_id";
	CmdArgInt opt_batch			('i', "index_of_batch", "<number>",
								"Align sequences with the specified batch number."
								"Otherwise defaults to all the outstanding batches.");
	opt_batch = -1;
	
	CmdArgStr opt_error_log 	('e', "error_log", "<string>",
								"file for logging errors. "
								"(defaults to STDERR).");
	CmdArgStr opt_blast_log		('b', "blast_log", "<string>",
								"file for logging bl2seq failures.");
	CmdArgStr opt_missing_seq	('m', "missing_sequences_log", "<string>",
								"file for logging gene pairs without Panda sequences.");

	string exe_file_name =  boost::filesystem::path(*argv).leaf();

		


		// construct command line
	CmdLine  cmdline(exe_file_name.c_str(),
							&opt_job_category,
							&opt_output_table,
							&opt_error_table,
							&opt_map_table,
							&opt_error_log,
							&opt_blast_log,
							&opt_missing_seq,
							&opt_batch,
							&opt_dbname,
							&opt_host,
							&opt_user,
							&opt_password,
							&opt_login,

							&opt_help,
							&opt_verbose,
							0);

	// parse command line
	CmdArgvIter  argv_iter(--argc, ++argv);

	cmdline.description( "This program calculates local alignments for specified gene "
							"pairs.\n\n"
							"Certain PostgreSQL tables are required:\n"
							"TABLE: batch_jobs "
							"(batch, checked_in, checked_out, machine, category, "
							"checked_out_when, ...)"								"\n"
							"TABLE: batch_gene_pairs "
							"(batch, gene_id1, gene_id2, category, ...)"			"\n"
							"TABLE: sequences "
							"(pi, sequence, ...)"									"\n"
							"MAP TABLE:  (default = ens_id)"				
							"(gene_id, pi, ..."										"\n"
							"FAILED TABLE:  "				
							"(gene_id1 TEXT, gene_id2 TEXT, message TEXT "
							"OUTPUT TABLE:  "				
							"(gene_id1, gene_id2, acc_code1, acc_code2, pi1, pi2, "
							"bl2seq_bitscore,  bl2seq_align_start, bl2seq_align_len, "
							"bl2seq_total_len, bl2seq_coverage, bl2seq_e_value, "
							"aln_gaps1, aln_gaps2, ...)"							"\n"
							"If the log file names contain the term %PID%, this will be "
							"replaced by the unique postgreSQL server process ID\n"
						);
	if (cmdline.parse(argv_iter))
		return false;



	// batch jobs
	args.job_category   =   opt_job_category.str();
	args.output_table	=   opt_output_table.str();
	args.map_table		=   opt_map_table.str();
	args.error_table    =	opt_error_table.str();


	// define verbose first before any error messages generated
	args.verbose	= opt_verbose;


	// initialize postgresql login
	args.db_login = "dbname=" +opt_dbname.str();
	
	string user		= opt_user;
	if (opt_user.str().length())
		args.db_login += " user=" + opt_user.str();
	else
		args.db_login += " user=postgres";
	
	if (opt_host.str().length())
		args.db_login += " host=" + opt_host.str();
	
	if (opt_password.str().length())
		args.db_login += " password=" + opt_password.str();

	if (opt_login.str().length())
		args.db_login += ' ' + opt_login.str();
	
	args.blast_log_name		= opt_blast_log.str();
	args.error_log_name		= opt_error_log.str();
	args.missing_log_name	= opt_missing_seq.str();

	int batch_index = opt_batch;
	if (batch_index < 0)
	{
		args.use_batch = false;
	}
	else
	{
		args.use_batch = true;
		args.batch = (unsigned)batch_index;
	}
	
	return true;
}


bool t_program_args::open_log_files(const std::string& PID)
{
	str_search_and_replace(blast_log_name  , "%PID%", PID);
	str_search_and_replace(error_log_name  , "%PID%", PID);
	str_search_and_replace(missing_log_name, "%PID%", PID);
	
	// make sure the blast log file is valid
	log_blast_errors	= blast_log_name.length();
	if (log_blast_errors)
	{
		f_blast_log.open(blast_log_name.c_str(), std::ios_base::out | std::ios_base::ate);
		if (!f_blast_log.good())
		{
			cerr << "ERROR!! Could not open the blast error log file (" << blast_log_name << ").\n";
			return(false);
		}
	}
	
	// make sure the error log file is valid
	log_errors			= error_log_name.length();
	if (log_errors)
	{
		f_error_log.open(error_log_name.c_str(), std::ios_base::out | std::ios_base::ate);
		if (!f_error_log.good())
		{
			cerr << "ERROR!! Could not open the error log file (" << error_log_name << ").\n";
			return(false);
		}
	}
	
	// make sure the error log file is valid
	log_missing			= missing_log_name.length();
	if (log_missing)
	{
		f_missing_log.open(missing_log_name.c_str(), std::ios_base::out | std::ios_base::ate);
		if (!f_missing_log.good())
		{
			cerr << "ERROR!! Could not open the log file for missing sequences ("
						<< missing_log_name << ").\n";
			return(false);
		}
	}
	return true;
}

